package com.zoz.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.util.FileUtils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;

/**
 * File工具类，扩展 hutool 工具包
 * @author Zheng Jie
 * @date 2018-12-27
 */

public class FileUtil extends cn.hutool.core.io.FileUtil {
   
	private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
    /**
     * 定义GB的计算常量
     */
    private static final int GB = 1024 * 1024 * 1024;
    /**
     * 定义MB的计算常量
     */
    private static final int MB = 1024 * 1024;
    /**
     * 定义KB的计算常量
     */
    private static final int KB = 1024;

    /**
     * 格式化小数
     */
    private static final DecimalFormat DF = new DecimalFormat("0.00");

    /**
     * MultipartFile转File
     */
    public static File toFile(MultipartFile multipartFile){
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix="."+getExtensionName(fileName);
        File file = null;
        try {
            // 用uuid作为文件名，防止生成的临时文件重复
            file = File.createTempFile(IdUtil.simpleUUID(), prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        } catch (IOException e) {
        	logger.error("MultipartFile转File失败", e);
        }
        return file;
    }

    /**
     * 获取文件扩展名，不带 .
     */
    public static String getExtensionName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot >-1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot >-1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    /**
     * 文件大小转换
     */
    public static String getSize(long size){
        String resultSize;
        if (size / GB >= 1) {
            //如果当前Byte的值大于等于1GB
            resultSize = DF.format(size / (float) GB) + "GB   ";
        } else if (size / MB >= 1) {
            //如果当前Byte的值大于等于1MB
            resultSize = DF.format(size / (float) MB) + "MB   ";
        } else if (size / KB >= 1) {
            //如果当前Byte的值大于等于1KB
            resultSize = DF.format(size / (float) KB) + "KB   ";
        } else {
            resultSize = size + "B   ";
        }
        return resultSize;
    }

    /**
     * inputStream 转 File
     */
   public static File inputStreamToFile(InputStream ins, String name) throws Exception{
        File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
        if (file.exists()) {
            return file;
        }
        try (OutputStream os = new FileOutputStream(file);){
        	 int bytesRead;
             int len = 8192;
             byte[] buffer = new byte[len];
             while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
                 os.write(buffer, 0, bytesRead);
             }
        }
        return file;
    }

    /**
     * 将文件名解析成文件的上传路径
     */
    public static File upload(MultipartFile file, String filePath) {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
        String name = getFileNameNoEx(file.getOriginalFilename());
        String suffix = getExtensionName(file.getOriginalFilename());
        String nowStr = "-" + format.format(date);
        try {
            String fileName = name + nowStr + "." + suffix;
            String path = filePath + fileName;
            // getCanonicalFile 可解析正确各种路径
            File dest = new File(path).getCanonicalFile();
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            // 文件写入
            file.transferTo(dest);
            return dest;
        } catch (Exception e) {
        	logger.error("将文件名解析成文件的上传路径失败", e);
        }
        return null;
    }

    public static String fileToBase64(File file) throws Exception {
    	String base64 = "";
        try(FileInputStream inputFile = new FileInputStream(file);){
            byte[] buffer = new byte[(int)file.length()];
            base64=Base64.encode(buffer);
        }
        return base64.replaceAll("[\\s*\t\n\r]", "");
    }

    /**
     * 导出excel
     */
    public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
        String tempPath =System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx";
        File file = new File(tempPath);
        BigExcelWriter writer= ExcelUtil.getBigWriter(file);
        // 一次性写出内容，使用默认样式，强制输出标题
        writer.write(list, true);
        //response为HttpServletResponse对象
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition","attachment;filename=file.xlsx");
        ServletOutputStream out=response.getOutputStream();
        // 终止后删除临时文件
        file.deleteOnExit();
        writer.flush(out, true);
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    public static String getFileType(String type) {
        String documents = "txt doc pdf ppt pps xlsx xls docx";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if(image.contains(type)){
            return "图片";
        } else if(documents.contains(type)){
            return "文档";
        } else if(music.contains(type)){
            return "音乐";
        } else if(video.contains(type)){
            return "视频";
        } else {
            return "其他";
        }
    }

    public static String getFileTypeByMimeType(String type) {
        String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
        return mimeType.split("/")[0];
    }



    /**
     * 判断两个文件是否相同
     */
    public static boolean check(String file1Md5, String file2Md5) {
        return file1Md5.equals(file2Md5);
    }


    /**
     * 下载文件
     * @param request /
     * @param response /
     * @param file /
     */
    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file){
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setHeader("Content-Disposition", "attachment; filename="+file.getName());
        response.setContentType("application/force-download;charset=utf-8");
        response.addHeader("filename", file.getName());
        byte[] buffer = new byte[1024];
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis)) {

            OutputStream os = response.getOutputStream();

            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
            response.flushBuffer();
        }
         catch (Exception e) {
        	 logger.error("下载文件失败", e);
        } 
    }


    /**
     * 根据路径获得两级路径模板
     * @author zhuhg
     * 2020年6月4日 下午7:39:58
     */
    public static List<String> getPathFiles(String readPath){
    	List<String> paths = new ArrayList<>();
    	
    	File path = new File(readPath);
    	readFilePath("",path.listFiles(),paths);
		return paths;
    }
    /**
     * 读取当前文件路径
     * @author zhuhg
     * 2020年6月4日 下午7:42:35
     */
    private static void readFilePath(String name,File[] lists,List<String> paths) {
    	//为空不便利
    	if(null == lists || lists.length == 0) {
    		return;
    	}
    	for (File file : lists) {
    		//获得路径名称
    		String fileName = name + File.separator + file.getName();
    		if(file.isFile()) {
    			paths.add(fileName) ;
    			continue;
    		}
    		
    		if(file.isDirectory()) {
    			readFilePath(fileName,file.listFiles(),paths);
    		}
		}
    }
    /**
     * 压缩目录下的文件
     * @param filePath 要压缩的目录路径
     * @param zipPath 生成的压缩包存放路径
     * @throws FileNotFoundException
     */
    public static void zipMutilFile(String filePath, String zipPath){
        File file = new File(filePath);
        if (!file.isDirectory()) {
        	logger.error("This file is not a directory.");
        	return;
        }
        File zipFile = new File(zipPath);
        try(ZipOutputStream zipOutputStream  = new ZipOutputStream(new FileOutputStream(zipFile)); ) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                try(InputStream inputStream = new FileInputStream(file1);){
                	zipOutputStream.putNextEntry(new ZipEntry(file.getName() + File.separator + file1.getName()));
                    int temp = 0;
                    while ((temp = inputStream.read()) != -1) {
                        zipOutputStream.write(temp);
                    }
                }
                
            }
        }  catch (Exception e) {
        	logger.error("压缩目录下的文件失败", e);
        }
    }
    /**
     * 把文件集合打成zip压缩包
     * @param srcFiles 压缩文件集合
     * @param zipFile  zip文件名
     * @throws RuntimeException 异常
     */
    public static void toZip(List<File> srcFiles, File zipFile){
        if(zipFile == null){
        	logger.error("压缩包文件名为空！");
        	return;
        }
        if(!zipFile.getName().endsWith(".zip")){
        	logger.error("压缩包文件名异常，zipFile={}" , zipFile.getPath());
        	return;
        }
        try (FileOutputStream out = new FileOutputStream(zipFile);
        		ZipOutputStream zos = new ZipOutputStream(out); 
        		){
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[StreamUtils.BUFFER_SIZE];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                try(FileInputStream in = new FileInputStream(srcFile);){
                	 while ((len = in.read(buf)) != -1) {
                         zos.write(buf, 0, len);
                     }
                }
            }
            zos.closeEntry();
        } catch (Exception e) {
            logger.error("把文件集合打成zip压缩包失败",e);
        } 
    }
    
    /**
     * 根据目录删除文件
     *@author zhuhg
     *@date 2020年6月8日 下午2:42:06
     * 
     * @param file
     */
    public static void deleteFolder(String filePath){
    	File file = new File(filePath);
    	FileUtils.delete(file);
    }
}
